#include "pch.h"
#include "D3D11.h"

using namespace Platform;
using namespace DX4WRT::Direct3D11;

IDevice^ Direct3D11::CreateDevice (DX4WRT::DXGI::IAdapter^ adapter, DX4WRT::Direct3D::DriverType driverType, DeviceCreate flags, array<DX4WRT::Direct3D::FeatureLevel>^ featureLevels)
{
	if (featureLevels == nullptr || featureLevels->Length == 0)
		throw ref new Platform::InvalidArgumentException ();

    D3D_FEATURE_LEVEL* Levels = new D3D_FEATURE_LEVEL[featureLevels->Length];

	for (int i = 0 ; i < featureLevels->Length ; i++)
		Levels[i] = (D3D_FEATURE_LEVEL)featureLevels[i];

	IDXGIAdapter* pAdapter = nullptr;

	if (adapter != nullptr)
	{
		Platform::IntPtr adapterPtr;
		adapter->GetInternal (&adapterPtr);
		pAdapter = (IDXGIAdapter*)(void*)adapterPtr;
	}

	ID3D11Device* device;
    ID3D11DeviceContext* context;

	D3D_FEATURE_LEVEL featureLevel;
    
    HRESULT hr =  D3D11CreateDevice(
			pAdapter,
            (D3D_DRIVER_TYPE)driverType,
            nullptr,                  
            (UINT)flags,              
            Levels,
            featureLevels->Length,
            D3D11_SDK_VERSION,
            &device,
            &featureLevel,
            &context
            );

	delete [] Levels;

	if (context != NULL)
		context->Release ();

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new Direct3D11Device (device);
}

ITexture2D^ Direct3D11::GetSwapChainBuffer (DX4WRT::DXGI::ISwapChain^swapChain, uint32 buffer)
{
	if (swapChain == nullptr)
		return nullptr;

	ID3D11Texture2D* pTexture;

	Platform::IntPtr SC;

	swapChain->GetInternal (&SC);

	IDXGISwapChain* pSwapChain = (IDXGISwapChain*)(void*)SC;

	HRESULT hr = pSwapChain->GetBuffer (buffer, __uuidof(pTexture), (void**)&pTexture);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new Texture2D (pTexture);
}

///////////////////////////////////////////////////////////////////////////////////////////////////

IBuffer^ Direct3D11Device::CreateBuffer (BufferDescription^ description, SubresourceData^ initialData)
{
	ID3D11Buffer* pBuffer;

	D3D11_SUBRESOURCE_DATA* pData = NULL;

	// TODO

	HRESULT hr = m_Device->CreateBuffer (&(description->m_Desc), pData, &pBuffer);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new Buffer (pBuffer);
}

ITexture1D^ Direct3D11Device::CreateTexture1D(Texture1DDescription^ description, array<SubresourceData^>^ initialData)
{
	ID3D11Texture1D* pTexture1D;

	D3D11_SUBRESOURCE_DATA* pData = NULL;

	// TODO

	HRESULT hr = m_Device->CreateTexture1D (&(description->m_Desc), pData, &pTexture1D);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new Texture1D (pTexture1D);
}

ITexture2D^ Direct3D11Device::CreateTexture2D(Texture2DDescription^ description, array<SubresourceData^>^ initialData) 
{
	ID3D11Texture2D* pTexture2D;

	D3D11_SUBRESOURCE_DATA* pData = NULL;

	// TODO

	HRESULT hr = m_Device->CreateTexture2D (&(description->m_Desc), pData, &pTexture2D);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new Texture2D (pTexture2D);
}

ITexture3D^ Direct3D11Device::CreateTexture3D(Texture3DDescription^ description, array<SubresourceData^>^ initialData) 
{
	ID3D11Texture3D* pTexture3D;

	D3D11_SUBRESOURCE_DATA* pData = NULL;

	// TODO

	HRESULT hr = m_Device->CreateTexture3D (&(description->m_Desc), pData, &pTexture3D);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new Texture3D (pTexture3D);
}

IShaderResourceView^ Direct3D11Device::CreateShaderResourceView (IResource^ resource, ShaderResourceViewDescription^ description)
{
	ID3D11ShaderResourceView* pView;

	HRESULT hr = m_Device->CreateShaderResourceView (((Resource^)resource)->GetNativeResource(), description != nullptr ? &(description->m_Desc) : NULL, &pView);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new ShaderResourceView (pView);
}

IUnorderedAccessView^ Direct3D11Device::CreateUnorderedAccessView (IResource^ resource, UnorderedAccessViewDescription^ description)
{
	ID3D11UnorderedAccessView* pView;

	HRESULT hr = m_Device->CreateUnorderedAccessView (((Resource^)resource)->GetNativeResource(), description != nullptr ? &(description->m_Desc) : NULL, &pView);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new UnorderedAccessView (pView);
}

IRenderTargetView^ Direct3D11Device::CreateRenderTargetView (IResource^ resource, RenderTargetViewDescription^ description)
{
	ID3D11RenderTargetView* pView;

	HRESULT hr = m_Device->CreateRenderTargetView (((Resource^)resource)->GetNativeResource(), description != nullptr ? &(description->m_Desc) : NULL, &pView);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new RenderTargetView (pView);
}

IDepthStencilView^ Direct3D11Device::CreateDepthStencilView (IResource^ resource, DepthStencilViewDescription^ description)
{
	ID3D11DepthStencilView* pView;

	HRESULT hr = m_Device->CreateDepthStencilView (((Resource^)resource)->GetNativeResource(), description != nullptr ? &(description->m_Desc) : NULL, &pView);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new DepthStencilView (pView);
}

IInputLayout^ Direct3D11Device::CreateInputLayout (array<InputElementDescription^>^ inputElementDescriptions, array<uint8>^shaderBytecodeWithInputSignature)
{
	ID3D11InputLayout* pLayout;

	D3D11_INPUT_ELEMENT_DESC* pDesc = nullptr;
	UINT elementCount = 0;

	if (inputElementDescriptions != nullptr && inputElementDescriptions->Length > 0)
	{
		pDesc = (D3D11_INPUT_ELEMENT_DESC*)_malloca (sizeof(D3D11_INPUT_ELEMENT_DESC)*inputElementDescriptions->Length);

		for (int i = 0 ; i < inputElementDescriptions->Length ; i++)
			memcpy (&pDesc[i], &(inputElementDescriptions[i]->m_Desc), sizeof(D3D11_INPUT_ELEMENT_DESC));
	}

	HRESULT hr = m_Device->CreateInputLayout (pDesc, elementCount, &shaderBytecodeWithInputSignature[0], shaderBytecodeWithInputSignature->Length, &pLayout);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	_freea (pDesc);

	return ref new InputLayout (pLayout);
}

IVertexShader^ Direct3D11Device::CreateVertexShader (array<uint8>^ shaderBytecode, IClassLinkage^ classLinkage)
{
	ID3D11VertexShader* pShader;

	HRESULT hr = m_Device->CreateVertexShader (&shaderBytecode[0], shaderBytecode->Length, classLinkage != nullptr ? ((ClassLinkage^)classLinkage)->GetNative() : nullptr, &pShader);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new VertexShader (pShader);
}

IGeometryShader^ Direct3D11Device::CreateGeometryShader (array<uint8>^ shaderBytecode, IClassLinkage^ classLinkage)
{
	ID3D11GeometryShader* pShader;

	HRESULT hr = m_Device->CreateGeometryShader (&shaderBytecode[0], shaderBytecode->Length, classLinkage != nullptr ? ((ClassLinkage^)classLinkage)->GetNative() : nullptr, &pShader);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new GeometryShader (pShader);
}

IGeometryShader^ Direct3D11Device::CreateGeometryShaderWithStreamOutput (array<uint8>^ shaderBytecode, array<StreamOutDeclarationEntry^>^ streamOutDeclaration, array<uint32>^ bufferStrides,  uint32 rasterizedStream, IClassLinkage^ classLinkage)
{
	ID3D11GeometryShader* pShader;

	D3D11_SO_DECLARATION_ENTRY* pEntries = NULL;
	UINT entryCount = 0;

	if (streamOutDeclaration != nullptr && streamOutDeclaration->Length > 0)
	{
		pEntries = (D3D11_SO_DECLARATION_ENTRY*)_malloca (sizeof(D3D11_SO_DECLARATION_ENTRY)*streamOutDeclaration->Length);

		for (int i = 0 ; i < streamOutDeclaration->Length ; i++)
			memcpy (&pEntries[i], &(streamOutDeclaration[0]->m_Decl), sizeof(D3D11_SO_DECLARATION_ENTRY));

		entryCount =  streamOutDeclaration->Length;
	}

	HRESULT hr = m_Device->CreateGeometryShaderWithStreamOutput (&shaderBytecode[0], shaderBytecode->Length, 
																 pEntries, entryCount,
																 &bufferStrides[0], bufferStrides->Length,
																 rasterizedStream,
															  	 classLinkage != nullptr ? ((ClassLinkage^)classLinkage)->GetNative() : nullptr,
																 &pShader);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	_freea (pEntries);

	return ref new GeometryShader (pShader);
}

IPixelShader^ Direct3D11Device::CreatePixelShader (array<uint8>^ shaderBytecode, IClassLinkage^ classLinkage)
{
	ID3D11PixelShader* pShader;

	HRESULT hr = m_Device->CreatePixelShader (&shaderBytecode[0], shaderBytecode->Length, classLinkage != nullptr ? ((ClassLinkage^)classLinkage)->GetNative() : nullptr, &pShader);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new PixelShader (pShader);
}

IHullShader^ Direct3D11Device::CreateHullShader (array<uint8>^ shaderBytecode, IClassLinkage^ classLinkage)
{
	ID3D11HullShader* pShader;

	HRESULT hr = m_Device->CreateHullShader (&shaderBytecode[0], shaderBytecode->Length, classLinkage != nullptr ? ((ClassLinkage^)classLinkage)->GetNative() : nullptr, &pShader);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new HullShader (pShader);
}

IDomainShader^ Direct3D11Device::CreateDomainShader (array<uint8>^ shaderBytecode, IClassLinkage^ classLinkage)
{
	ID3D11DomainShader* pShader;

	HRESULT hr = m_Device->CreateDomainShader (&shaderBytecode[0], shaderBytecode->Length, classLinkage != nullptr ? ((ClassLinkage^)classLinkage)->GetNative() : nullptr, &pShader);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new DomainShader (pShader);
}

IComputeShader^ Direct3D11Device::CreateComputeShader (array<uint8>^ shaderBytecode, IClassLinkage^ classLinkage)
{
	ID3D11ComputeShader* pShader;

	HRESULT hr = m_Device->CreateComputeShader (&shaderBytecode[0], shaderBytecode->Length, classLinkage != nullptr ? ((ClassLinkage^)classLinkage)->GetNative() : nullptr, &pShader);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new ComputeShader (pShader);
}

IClassLinkage^ Direct3D11Device::CreateClassLinkage ()
{
	ID3D11ClassLinkage* pLinkage;

	HRESULT hr = m_Device->CreateClassLinkage (&pLinkage);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new ClassLinkage (pLinkage);
}

IBlendState^ Direct3D11Device::CreateBlendState (BlendDescription^ description)
{
	ID3D11BlendState* pState;

	HRESULT hr = m_Device->CreateBlendState (&(description->m_Desc), &pState);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new BlendState (pState);
}

IDepthStencilState^ Direct3D11Device::CreateDepthStencilState (DepthStencilDescription^ description)
{
	ID3D11DepthStencilState* pState;

	HRESULT hr = m_Device->CreateDepthStencilState (&(description->m_Desc), &pState);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new DepthStencilState (pState);
}

IRasterizerState^ Direct3D11Device::CreateRasterizerState (RasterizerDescription^ description)
{
	ID3D11RasterizerState* pState;

	HRESULT hr = m_Device->CreateRasterizerState (&(description->m_Desc), &pState);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new RasterizerState (pState);
}

ISamplerState^ Direct3D11Device::CreateSamplerState (SamplerDescription^ description)
{
	ID3D11SamplerState* pState;

	HRESULT hr = m_Device->CreateSamplerState (&(description->m_Desc), &pState);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new SamplerState (pState);
}

IQuery^ Direct3D11Device::CreateQuery (QueryDescription^ description)
{
	ID3D11Query* pQuery;

	HRESULT hr = m_Device->CreateQuery (&(description->m_Desc), &pQuery);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new Query (pQuery);
}

IPredicate^ Direct3D11Device::CreatePredicate (QueryDescription^ description)
{
	ID3D11Predicate* pPredicate;

	HRESULT hr = m_Device->CreatePredicate (&(description->m_Desc), &pPredicate);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new Predicate (pPredicate);
}

ICounter^ Direct3D11Device::CreateCounter (CounterDescription^ description)
{
	ID3D11Counter* pCounter;

	HRESULT hr = m_Device->CreateCounter (&(description->m_Desc), &pCounter);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new Counter (pCounter);
}

IDeviceContext^ Direct3D11Device::CreateDeferredContext (uint32 contextFlags)
{
	ID3D11DeviceContext* pContext;

	HRESULT hr = m_Device->CreateDeferredContext (contextFlags, &pContext);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new DeviceContext (pContext);
}

uint32 Direct3D11Device::CheckMultisampleQualityLevels (DX4WRT::DXGI::Format format, uint32 sampleCount)
{
	UINT levels;

	HRESULT hr = m_Device->CheckMultisampleQualityLevels ((DXGI_FORMAT)format, sampleCount, &levels);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return levels;
}

DX4WRT::DXGI::IDevice^ Direct3D11Device::DXGIDevice::get ()
{
	return DXGI::DXGI::GetDeviceForObject (m_Device);
}

IDeviceContext^ Direct3D11Device::ImmediateContext::get()
{
	ID3D11DeviceContext* pContext;

	m_Device->GetImmediateContext (&pContext);

	// cache
	return ref new DeviceContext (pContext);
}

///////////////////////////////////////////////////////////////////////////////////////////////////

DeviceContext::DeviceContext (ID3D11DeviceContext* pDeviceContext)
	: m_pDeviceContext (pDeviceContext)
{
}

DeviceContext::~DeviceContext ()
{
	if (m_pDeviceContext != nullptr)
	{
		m_pDeviceContext->Release ();
		m_pDeviceContext = nullptr;
	}
}

void DeviceContext::VSSetConstantBuffers (uint32 startSlot, array<IBuffer^>^ constantBuffers)
{
	if (constantBuffers == nullptr || constantBuffers->Length == 0)
		return;

	ID3D11Buffer** pBuffers = (ID3D11Buffer**)_malloca(sizeof(ID3D11Buffer*)*constantBuffers->Length);

	for (int i = 0 ; i < constantBuffers->Length ; i++)
		pBuffers[i] = constantBuffers[i] != nullptr ? ((Buffer^)constantBuffers[i])->GetNative() : nullptr;

	m_pDeviceContext->VSSetConstantBuffers (startSlot, constantBuffers->Length, pBuffers);

	_freea (pBuffers);
}

void DeviceContext::PSSetShaderResources (uint32 startSlot, array<IShaderResourceView^>^ shaderResourceViews)
{
	if (shaderResourceViews == nullptr || shaderResourceViews->Length == 0)
		return;
	
	ID3D11ShaderResourceView** pShaderResourceViews = (ID3D11ShaderResourceView**)_malloca(sizeof(ID3D11ShaderResourceView*)*shaderResourceViews->Length);

	for (int i = 0 ; i < shaderResourceViews->Length ; i++)
		pShaderResourceViews[i] = shaderResourceViews[i] != nullptr ? ((ShaderResourceView^)shaderResourceViews[i])->GetNative() : nullptr;

	m_pDeviceContext->PSSetShaderResources (startSlot, shaderResourceViews->Length, pShaderResourceViews);

	_freea (pShaderResourceViews);
}

void DeviceContext::PSSetShader (IPixelShader^ pixelShader, array<IClassInstance^>^ classInstances)
{
	ID3D11PixelShader* pShader = pixelShader != nullptr ? ((PixelShader^)pixelShader)->GetNative() : nullptr;

	ID3D11ClassInstance** pClassInstances = nullptr;
	UINT classInstancesCount = 0;

	if (classInstances != nullptr && classInstances->Length > 0)
	{
		pClassInstances = (ID3D11ClassInstance**)_malloca(sizeof(ID3D11ClassInstance*)*classInstances->Length);

		for (int i = 0 ; i < classInstances->Length ; i++)
			pClassInstances[i] = classInstances[i] != nullptr ? ((ClassInstance^)classInstances[i])->GetNative() : nullptr;

		classInstancesCount = classInstances->Length;
	}

	m_pDeviceContext->PSSetShader (pShader, pClassInstances, classInstancesCount);

	_freea (pClassInstances);
}

void DeviceContext::PSSetSamplers (uint32 startSlot, array<ISamplerState^>^ samplerStates)
{
	if (samplerStates == nullptr || samplerStates->Length == 0)
		return;
	
	ID3D11SamplerState** pSamplerStates = (ID3D11SamplerState**)_malloca(sizeof(ID3D11SamplerState*)*samplerStates->Length);

	for (int i = 0 ; i < samplerStates->Length ; i++)
		pSamplerStates[i] = samplerStates[i] != nullptr ? ((SamplerState^)samplerStates[i])->GetNative() : nullptr;

	m_pDeviceContext->PSSetSamplers (startSlot, samplerStates->Length, pSamplerStates);

	_freea (pSamplerStates);
}

void DeviceContext::VSSetShader (IVertexShader^ vertexShader, array<IClassInstance^>^ classInstances)
{
	ID3D11VertexShader* pShader = vertexShader != nullptr ? ((VertexShader^)vertexShader)->GetNative() : nullptr;

	ID3D11ClassInstance** pClassInstances = nullptr;
	UINT classInstancesCount = 0;

	if (classInstances != nullptr && classInstances->Length > 0)
	{
		pClassInstances = (ID3D11ClassInstance**)_malloca(sizeof(ID3D11ClassInstance*)*classInstances->Length);

		for (int i = 0 ; i < classInstances->Length ; i++)
			pClassInstances[i] = classInstances[i] != nullptr ? ((ClassInstance^)classInstances[i])->GetNative() : nullptr;

		classInstancesCount = classInstances->Length;
	}

	m_pDeviceContext->VSSetShader (pShader, pClassInstances, classInstancesCount);

	_freea (pClassInstances);
}

void DeviceContext::PSSetConstantBuffers (uint32 startSlot, array<IBuffer^>^ constantBuffers)
{
	if (constantBuffers == nullptr || constantBuffers->Length == 0)
		return;

	ID3D11Buffer** pBuffers = (ID3D11Buffer**)_malloca(sizeof(ID3D11Buffer*)*constantBuffers->Length);

	for (int i = 0 ; i < constantBuffers->Length ; i++)
		pBuffers[i] = constantBuffers[i] != nullptr ? ((Buffer^)constantBuffers[i])->GetNative() : nullptr;

	m_pDeviceContext->PSSetConstantBuffers (startSlot, constantBuffers->Length, pBuffers);

	_freea (pBuffers);
}

void DeviceContext::IASetInputLayout (IInputLayout^ inputLayout)
{
	m_pDeviceContext->IASetInputLayout (inputLayout != nullptr ? ((InputLayout^)inputLayout)->GetNative() : nullptr);
}

void DeviceContext::IASetVertexBuffers (uint32 startSlot, array<IBuffer^>^ vertexBuffers, array<uint32>^ strides, array<uint32>^ offsets)
{
	if (vertexBuffers == nullptr || vertexBuffers->Length == 0 ||
		strides == nullptr || strides->Length != vertexBuffers->Length ||
		offsets == nullptr || offsets->Length != vertexBuffers->Length)
		return;

	ID3D11Buffer** pBuffers = (ID3D11Buffer**)_malloca(sizeof(ID3D11Buffer*)*vertexBuffers->Length);
	UINT* pStrides = (UINT*)_malloca(sizeof(UINT)*strides->Length);
	UINT* pOffsets = (UINT*)_malloca(sizeof(UINT)*offsets->Length);
	
	for (int i = 0 ; i < vertexBuffers->Length ; i++)
	{
		pBuffers[i] = vertexBuffers[i] != nullptr ? ((Buffer^)vertexBuffers[i])->GetNative() : nullptr;
		pStrides[i] = strides[i];
		pOffsets[i] = offsets[i];
	}

	m_pDeviceContext->IASetVertexBuffers (startSlot, vertexBuffers->Length, pBuffers, pStrides, pOffsets);

	_freea (pOffsets);
	_freea (pStrides);
	_freea (pBuffers);
}

void DeviceContext::IASetIndexBuffer (IBuffer^ indexBuffer, DX4WRT::DXGI::Format format, uint32 offset)
{
	m_pDeviceContext->IASetIndexBuffer (indexBuffer != nullptr ? ((Buffer^)indexBuffer)->GetNative() : nullptr, (DXGI_FORMAT)format, offset);
}

void DeviceContext::GSSetConstantBuffers (uint32 startSlot, array<IBuffer^>^ constantBuffers)
{
	if (constantBuffers == nullptr || constantBuffers->Length == 0)
		return;

	ID3D11Buffer** pBuffers = (ID3D11Buffer**)_malloca(sizeof(ID3D11Buffer*)*constantBuffers->Length);

	for (int i = 0 ; i < constantBuffers->Length ; i++)
		pBuffers[i] = constantBuffers[i] != nullptr ? ((Buffer^)constantBuffers[i])->GetNative() : nullptr;

	m_pDeviceContext->GSSetConstantBuffers (startSlot, constantBuffers->Length, pBuffers);

	_freea (pBuffers);
}

void DeviceContext::GSSetShader (IGeometryShader^ geometryShader, array<IClassInstance^>^ classInstances)
{
	ID3D11GeometryShader* pShader = geometryShader != nullptr ? ((GeometryShader^)geometryShader)->GetNative() : nullptr;

	ID3D11ClassInstance** pClassInstances = nullptr;
	UINT classInstancesCount = 0;

	if (classInstances != nullptr && classInstances->Length > 0)
	{
		pClassInstances = (ID3D11ClassInstance**)_malloca(sizeof(ID3D11ClassInstance*)*classInstances->Length);

		for (int i = 0 ; i < classInstances->Length ; i++)
			pClassInstances[i] = classInstances[i] != nullptr ? ((ClassInstance^)classInstances[i])->GetNative() : nullptr;

		classInstancesCount = classInstances->Length;
	}

	m_pDeviceContext->GSSetShader (pShader, pClassInstances, classInstancesCount);

	_freea (pClassInstances);
}

void DeviceContext::VSSetShaderResources (uint32 startSlot, array<IShaderResourceView^>^ shaderResourceViews)
{
	if (shaderResourceViews == nullptr || shaderResourceViews->Length == 0)
		return;
	
	ID3D11ShaderResourceView** pShaderResourceViews = (ID3D11ShaderResourceView**)_malloca(sizeof(ID3D11ShaderResourceView*)*shaderResourceViews->Length);

	for (int i = 0 ; i < shaderResourceViews->Length ; i++)
		pShaderResourceViews[i] = shaderResourceViews[i] != nullptr ? ((ShaderResourceView^)shaderResourceViews[i])->GetNative() : nullptr;

	m_pDeviceContext->VSSetShaderResources (startSlot, shaderResourceViews->Length, pShaderResourceViews);

	_freea (pShaderResourceViews);
}

void DeviceContext::VSSetSamplers (uint32 startSlot, array<ISamplerState^>^ samplerStates)
{
	if (samplerStates == nullptr || samplerStates->Length == 0)
		return;
	
	ID3D11SamplerState** pSamplerStates = (ID3D11SamplerState**)_malloca(sizeof(ID3D11SamplerState*)*samplerStates->Length);

	for (int i = 0 ; i < samplerStates->Length ; i++)
		pSamplerStates[i] = samplerStates[i] != nullptr ? ((SamplerState^)samplerStates[i])->GetNative() : nullptr;

	m_pDeviceContext->VSSetSamplers (startSlot, samplerStates->Length, pSamplerStates);

	_freea (pSamplerStates);
}

void DeviceContext::Begin (IAsynchronous^ async)
{
	m_pDeviceContext->Begin (async != nullptr ? ((Asynchronous^)async)->GetNativeAsynchronous() : nullptr);
}

void DeviceContext::End (IAsynchronous^ async)
{
	m_pDeviceContext->End (async != nullptr ? ((Asynchronous^)async)->GetNativeAsynchronous() : nullptr);
}

void DeviceContext::SetPredication (IPredicate^ predicate, bool predicateValue)
{
	m_pDeviceContext->SetPredication (predicate != nullptr ? ((Predicate^)predicate)->GetNative() : nullptr, predicateValue);
}

void DeviceContext::GSSetShaderResources (uint32 startSlot, array<IShaderResourceView^>^ shaderResourceViews)
{
	if (shaderResourceViews == nullptr || shaderResourceViews->Length == 0)
		return;
	
	ID3D11ShaderResourceView** pShaderResourceViews = (ID3D11ShaderResourceView**)_malloca(sizeof(ID3D11ShaderResourceView*)*shaderResourceViews->Length);

	for (int i = 0 ; i < shaderResourceViews->Length ; i++)
		pShaderResourceViews[i] = shaderResourceViews[i] != nullptr ? ((ShaderResourceView^)shaderResourceViews[i])->GetNative() : nullptr;

	m_pDeviceContext->GSSetShaderResources (startSlot, shaderResourceViews->Length, pShaderResourceViews);

	_freea (pShaderResourceViews);
}

void DeviceContext::GSSetSamplers (uint32 startSlot, array<ISamplerState^>^ samplerStates)
{
	if (samplerStates == nullptr || samplerStates->Length == 0)
		return;
	
	ID3D11SamplerState** pSamplerStates = (ID3D11SamplerState**)_malloca(sizeof(ID3D11SamplerState*)*samplerStates->Length);

	for (int i = 0 ; i < samplerStates->Length ; i++)
		pSamplerStates[i] = samplerStates[i] != nullptr ? ((SamplerState^)samplerStates[i])->GetNative() : nullptr;

	m_pDeviceContext->GSSetSamplers (startSlot, samplerStates->Length, pSamplerStates);

	_freea (pSamplerStates);
}

void DeviceContext::OMSetRenderTargets (array<IRenderTargetView^>^ renderTargetViews, IDepthStencilView^ depthStencilView)
{
	ID3D11RenderTargetView** pRenderTargetViews = nullptr;
	UINT renderTargetViewsCount = 0;

	if (renderTargetViews != nullptr && renderTargetViews->Length > 0)
	{
		pRenderTargetViews = (ID3D11RenderTargetView**)_malloca(sizeof(ID3D11RenderTargetView*)*renderTargetViews->Length);

		for (int i = 0 ; i < renderTargetViews->Length ; i++)
			pRenderTargetViews[i] = renderTargetViews[i] != nullptr ? ((RenderTargetView^)renderTargetViews[i])->GetNative() : nullptr;

		renderTargetViewsCount = renderTargetViews->Length;
	}

	m_pDeviceContext->OMSetRenderTargets (renderTargetViewsCount, pRenderTargetViews, depthStencilView != nullptr ? ((DepthStencilView^)depthStencilView)->GetNative() : nullptr);

	_freea (pRenderTargetViews);
}

void DeviceContext::OMSetRenderTargetsAndUnorderedAccessViews (array<IRenderTargetView^>^ renderTargetViews, IDepthStencilView^ depthStencilView, uint32 uAVStartSlot, array<IUnorderedAccessView^>^ unorderedAccessViews, array<uint32>^ uAVInitialCounts)
{
	ID3D11RenderTargetView** pRenderTargetViews = nullptr;
	UINT renderTargetViewsCount = 0;

	if (renderTargetViews != nullptr && renderTargetViews->Length > 0)
	{
		pRenderTargetViews = (ID3D11RenderTargetView**)_malloca(sizeof(ID3D11RenderTargetView*)*renderTargetViews->Length);

		for (int i = 0 ; i < renderTargetViews->Length ; i++)
			pRenderTargetViews[i] = renderTargetViews[i] != nullptr ? ((RenderTargetView^)renderTargetViews[i])->GetNative() : nullptr;

		renderTargetViewsCount = renderTargetViews->Length;
	}

	ID3D11UnorderedAccessView** pUnorderedAccessViews = nullptr;
	UINT* pUAVInitialCounts = nullptr;
	UINT unorderedAccessViewsCount = 0;

	if (unorderedAccessViews != nullptr && unorderedAccessViews->Length > 0)
	{
		pUnorderedAccessViews = (ID3D11UnorderedAccessView**)_malloca(sizeof(ID3D11UnorderedAccessView*)*unorderedAccessViews->Length);
		pUAVInitialCounts = (UINT*)_malloca(sizeof(UINT)*uAVInitialCounts->Length);

		for (int i = 0 ; i < unorderedAccessViews->Length ; i++)
		{
			pUnorderedAccessViews[i] = unorderedAccessViews[i] != nullptr ? ((UnorderedAccessView^)unorderedAccessViews[i])->GetNative() : nullptr;
			pUAVInitialCounts[i] = uAVInitialCounts[i];
		}

		unorderedAccessViewsCount = unorderedAccessViews->Length;
	}

	m_pDeviceContext->OMSetRenderTargetsAndUnorderedAccessViews (renderTargetViewsCount, pRenderTargetViews, depthStencilView != nullptr ? ((DepthStencilView^)depthStencilView)->GetNative() : nullptr, uAVStartSlot, unorderedAccessViewsCount, pUnorderedAccessViews, pUAVInitialCounts);

	_freea (pUAVInitialCounts);
	_freea (pUnorderedAccessViews);
	_freea (pRenderTargetViews);
}

void DeviceContext::OMSetBlendState (IBlendState^ blendState, array<float>^ blendfactor, uint32 sampleMask)
{
	float BlendFactor[4];

	if (blendfactor != nullptr)
		for (int i = 0 ; i < min (4, blendfactor->Length) ; i++)
			BlendFactor[i] = blendfactor[i];

	m_pDeviceContext->OMSetBlendState (blendState != nullptr ? ((BlendState^)blendState)->GetNative() : nullptr, BlendFactor, sampleMask);
}

void DeviceContext::OMSetDepthStencilState ( IDepthStencilState^ depthStencilState, uint32 stencilRef)
{
	m_pDeviceContext->OMSetDepthStencilState (depthStencilState != nullptr ? ((DepthStencilState^)depthStencilState)->GetNative() : nullptr , stencilRef);
}

void DeviceContext::SOSetTargets (array<IBuffer^>^ targets, array<uint32>^ offsets)
{
	ID3D11Buffer** pTargets = nullptr;
	UINT* pOffsets = nullptr;
	UINT targetsCount = 0;

	if (targets != nullptr && targets->Length > 0)
	{
		pTargets = (ID3D11Buffer**)_malloca(sizeof(ID3D11Buffer*)*targets->Length);
		pOffsets = (UINT*)_malloca(sizeof(UINT)*offsets->Length);

		for (int i = 0 ; i < targets->Length ; i++)
		{
			pTargets[i] = targets[i] != nullptr ? ((Buffer^)targets[i])->GetNative() : nullptr;
			pOffsets[i] = offsets[i];
		}

		targetsCount = targets->Length;
	}

	m_pDeviceContext->SOSetTargets (targetsCount, pTargets, pOffsets);

	_freea (pOffsets);
	_freea (pTargets);
}

void DeviceContext::DrawIndexedInstancedIndirect (IBuffer^ bufferForArgs, uint32 alignedByteOffsetForArgs)
{
	m_pDeviceContext->DrawIndexedInstancedIndirect (bufferForArgs != nullptr ? ((Buffer^)bufferForArgs)->GetNative() : nullptr , alignedByteOffsetForArgs);
}

void DeviceContext::DrawInstancedIndirect (IBuffer^ bufferForArgs, uint32 alignedByteOffsetForArgs)
{
	m_pDeviceContext->DrawInstancedIndirect (bufferForArgs != nullptr ? ((Buffer^)bufferForArgs)->GetNative() : nullptr , alignedByteOffsetForArgs);
}

void DeviceContext::DispatchIndirect (IBuffer^ bufferForArgs, uint32 alignedByteOffsetForArgs)
{
	m_pDeviceContext->DispatchIndirect (bufferForArgs != nullptr ? ((Buffer^)bufferForArgs)->GetNative() : nullptr , alignedByteOffsetForArgs);
}

void DeviceContext::RSSetState (IRasterizerState^ rasterizerState)
{
	m_pDeviceContext->RSSetState (rasterizerState != nullptr ? ((RasterizerState^)rasterizerState)->GetNative() : nullptr);
}

void DeviceContext::RSSetViewports (array<Viewport^>^ viewports)
{
	D3D11_VIEWPORT* pViewports = nullptr;
	UINT viewportCount = 0;

	if (viewports != nullptr && viewports->Length > 0)
	{
		pViewports = (D3D11_VIEWPORT*)_malloca(sizeof(D3D11_VIEWPORT)*viewports->Length);

		for (int i = 0 ; i < viewports->Length ; i++)
			memcpy (&pViewports[i], &(viewports[i]->m_Viewport), sizeof(D3D11_VIEWPORT));

		viewportCount = viewports->Length;
	}

	m_pDeviceContext->RSSetViewports (viewportCount, pViewports);

	_freea (pViewports);
}

void DeviceContext::RSSetScissorRects (array<Rect^>^ rects)
{
	D3D11_RECT* pRects = nullptr;
	UINT rectCount = 0;

	if (rects != nullptr && rects->Length > 0)
	{
		pRects = (D3D11_RECT*)_malloca(sizeof(D3D11_RECT)*rects->Length);

		for (int i = 0 ; i < rects->Length ; i++)
			memcpy (&pRects[i], &(rects[i]->m_Rect), sizeof(D3D11_RECT));

		rectCount = rects->Length;
	}

	m_pDeviceContext->RSSetScissorRects (rectCount, pRects);

	_freea (pRects);
}

void DeviceContext::CopySubresourceRegion (IResource^ destinationResource, uint32 destinationSubresource, uint32 destinationX, uint32 destinationY, uint32 destinationZ, IResource^ sourceResource, uint32 sourceSubresource, Box^ sourceBox)
{
	m_pDeviceContext->CopySubresourceRegion (destinationResource != nullptr ? ((Resource^)destinationResource)->GetNativeResource() : nullptr, destinationSubresource,
											 destinationX, destinationY, destinationZ,
											 sourceResource != nullptr ? ((Resource^)sourceResource)->GetNativeResource() : nullptr, sourceSubresource,
											 sourceBox != nullptr ? &(sourceBox->m_Box) : NULL);
}

void DeviceContext::CopyResource (IResource^ destinationResource, IResource^ sourceResource)
{
	m_pDeviceContext->CopyResource (destinationResource != nullptr ? ((Resource^)destinationResource)->GetNativeResource() : nullptr, sourceResource != nullptr ? ((Resource^)sourceResource)->GetNativeResource() : nullptr);
}

void DeviceContext::UpdateSubresource (IResource^ destinationResource, uint32 destinationSubresource, Box^ destinationBox, array<uint8>^ sourceData, uint32 sourceRowPitch, uint32 sourceDepthPitch)
{
	m_pDeviceContext->UpdateSubresource (destinationResource != nullptr ? ((Resource^)destinationResource)->GetNativeResource() : nullptr, destinationSubresource,
										 destinationBox != nullptr ? &(destinationBox->m_Box) : NULL,
										 &sourceData[0], sourceRowPitch, sourceDepthPitch);
}

void DeviceContext::CopyStructureCount (IBuffer^ destinationBuffer, uint32 destinationAlignedByteOffset, IUnorderedAccessView^ sourceView)
{
	m_pDeviceContext->CopyStructureCount (destinationBuffer != nullptr ?((Buffer^)destinationBuffer)->GetNative() : nullptr, destinationAlignedByteOffset, sourceView != nullptr ? ((UnorderedAccessView^)sourceView)->GetNative() : nullptr);
}

void DeviceContext::ClearRenderTargetView (IRenderTargetView^ rendertTargetView, array<float>^ colorRGBA)
{
	float Color[4];

	if (colorRGBA != nullptr)
		for (int i = 0 ; i < min (4, colorRGBA->Length) ; i++)
			Color[i] = colorRGBA[i];

	m_pDeviceContext->ClearRenderTargetView (rendertTargetView != nullptr ? ((RenderTargetView^)rendertTargetView)->GetNative() : nullptr, Color);
}

void DeviceContext::ClearUnorderedAccessViewUint (IUnorderedAccessView^ unorderedAccessView, array<uint32>^ values)
{
	UINT Values[4];

	if (values != nullptr)
		for (int i = 0 ; i < min (4, values->Length) ; i++)
			Values[i] = values[i];

	m_pDeviceContext->ClearUnorderedAccessViewUint (unorderedAccessView != nullptr ? ((UnorderedAccessView^)unorderedAccessView)->GetNative() : nullptr, Values);
}

void DeviceContext::ClearUnorderedAccessViewFloat (IUnorderedAccessView^ unorderedAccessView, array<float>^ values)
{
	float Values[4];

	if (values != nullptr)
		for (int i = 0 ; i < min (4, values->Length) ; i++)
			Values[i] = values[i];

	m_pDeviceContext->ClearUnorderedAccessViewFloat (unorderedAccessView != nullptr ? ((UnorderedAccessView^)unorderedAccessView)->GetNative() : nullptr, Values);
}

void DeviceContext::ClearDepthStencilView (IDepthStencilView^ depthStencilView, Clear clear, float depth, uint8 stencil)
{
	m_pDeviceContext->ClearDepthStencilView (depthStencilView != nullptr ? ((DepthStencilView^)depthStencilView)->GetNative() : nullptr, (UINT)clear, depth, stencil);
}

void DeviceContext::GenerateMips (IShaderResourceView^ shaderResourceView)
{
	m_pDeviceContext->GenerateMips (shaderResourceView != nullptr ? ((ShaderResourceView^)shaderResourceView)->GetNative() : nullptr);
}

void DeviceContext::SetResourceMinLOD (IResource^ resource, float minLOD)
{
	m_pDeviceContext->SetResourceMinLOD (resource != nullptr ? ((Resource^)resource)->GetNativeResource() : nullptr, minLOD);
}

float DeviceContext::GetResourceMinLOD (IResource^ resource)
{
	return m_pDeviceContext->GetResourceMinLOD (resource != nullptr ? ((Resource^)resource)->GetNativeResource() : nullptr);
}

void DeviceContext::ResolveSubresource (IResource^ destinationResource, uint32 destinationSubresource, IResource^ sourceResource, uint32 sourceSubresource, DX4WRT::DXGI::Format format)
{
	m_pDeviceContext->ResolveSubresource (destinationResource != nullptr ? ((Resource^)destinationResource)->GetNativeResource() : nullptr, destinationSubresource,
										  sourceResource != nullptr ? ((Resource^)sourceResource)->GetNativeResource() : nullptr, sourceSubresource,
										  (DXGI_FORMAT)format);
}

void DeviceContext::ExecuteCommandList(ICommandList^ commandList, bool restoreContextState)
{
	m_pDeviceContext->ExecuteCommandList (commandList != nullptr ? ((CommandList^)commandList)->GetNative() : nullptr, restoreContextState);
}

void DeviceContext::HSSetShaderResources (uint32 startSlot, array<IShaderResourceView^>^ shaderResourceViews)
{
	if (shaderResourceViews == nullptr || shaderResourceViews->Length == 0)
		return;
	
	ID3D11ShaderResourceView** pShaderResourceViews = (ID3D11ShaderResourceView**)_malloca(sizeof(ID3D11ShaderResourceView*)*shaderResourceViews->Length);

	for (int i = 0 ; i < shaderResourceViews->Length ; i++)
		pShaderResourceViews[i] = shaderResourceViews[i] != nullptr ? ((ShaderResourceView^)shaderResourceViews[i])->GetNative() : nullptr;

	m_pDeviceContext->HSSetShaderResources (startSlot, shaderResourceViews->Length, pShaderResourceViews);

	_freea (pShaderResourceViews);
}

void DeviceContext::HSSetShader (IHullShader^ hullShader, array<IClassInstance^>^ classInstances)
{
	ID3D11HullShader* pShader = hullShader != nullptr ? ((HullShader^)hullShader)->GetNative() : nullptr;

	ID3D11ClassInstance** pClassInstances = nullptr;
	UINT classInstancesCount = 0;

	if (classInstances != nullptr && classInstances->Length > 0)
	{
		pClassInstances = (ID3D11ClassInstance**)_malloca(sizeof(ID3D11ClassInstance*)*classInstances->Length);

		for (int i = 0 ; i < classInstances->Length ; i++)
			pClassInstances[i] = classInstances[i] != nullptr ? ((ClassInstance^)classInstances[i])->GetNative() : nullptr;

		classInstancesCount = classInstances->Length;
	}

	m_pDeviceContext->HSSetShader (pShader, pClassInstances, classInstancesCount);

	_freea (pClassInstances);
}

void DeviceContext::HSSetSamplers (uint32 startSlot, array<ISamplerState^>^ samplerStates)
{
	if (samplerStates == nullptr || samplerStates->Length == 0)
		return;
	
	ID3D11SamplerState** pSamplerStates = (ID3D11SamplerState**)_malloca(sizeof(ID3D11SamplerState*)*samplerStates->Length);

	for (int i = 0 ; i < samplerStates->Length ; i++)
		pSamplerStates[i] = samplerStates[i] != nullptr ? ((SamplerState^)samplerStates[i])->GetNative() : nullptr;

	m_pDeviceContext->HSSetSamplers (startSlot, samplerStates->Length, pSamplerStates);

	_freea (pSamplerStates);
}

void DeviceContext::HSSetConstantBuffers (uint32 startSlot, array<IBuffer^>^ constantBuffers)
{
	if (constantBuffers == nullptr || constantBuffers->Length == 0)
		return;

	ID3D11Buffer** pBuffers = (ID3D11Buffer**)_malloca(sizeof(ID3D11Buffer*)*constantBuffers->Length);

	for (int i = 0 ; i < constantBuffers->Length ; i++)
		pBuffers[i] = constantBuffers[i] != nullptr ? ((Buffer^)constantBuffers[i])->GetNative() : nullptr;

	m_pDeviceContext->HSSetConstantBuffers (startSlot, constantBuffers->Length, pBuffers);

	_freea (pBuffers);
}

void DeviceContext::DSSetShaderResources (uint32 startSlot, array<IShaderResourceView^>^ shaderResourceViews)
{
	if (shaderResourceViews == nullptr || shaderResourceViews->Length == 0)
		return;
	
	ID3D11ShaderResourceView** pShaderResourceViews = (ID3D11ShaderResourceView**)_malloca(sizeof(ID3D11ShaderResourceView*)*shaderResourceViews->Length);

	for (int i = 0 ; i < shaderResourceViews->Length ; i++)
		pShaderResourceViews[i] = shaderResourceViews[i] != nullptr ? ((ShaderResourceView^)shaderResourceViews[i])->GetNative() : nullptr;

	m_pDeviceContext->DSSetShaderResources (startSlot, shaderResourceViews->Length, pShaderResourceViews);

	_freea (pShaderResourceViews);
}

void DeviceContext::DSSetShader (IDomainShader^ domainShader, array<IClassInstance^>^ classInstances)
{
	ID3D11DomainShader* pShader = domainShader != nullptr ? ((DomainShader^)domainShader)->GetNative() : nullptr;

	ID3D11ClassInstance** pClassInstances = nullptr;
	UINT classInstancesCount = 0;

	if (classInstances != nullptr && classInstances->Length > 0)
	{
		pClassInstances = (ID3D11ClassInstance**)_malloca(sizeof(ID3D11ClassInstance*)*classInstances->Length);

		for (int i = 0 ; i < classInstances->Length ; i++)
			pClassInstances[i] = classInstances[i] != nullptr ? ((ClassInstance^)classInstances[i])->GetNative() : nullptr;

		classInstancesCount = classInstances->Length;
	}

	m_pDeviceContext->DSSetShader (pShader, pClassInstances, classInstancesCount);

	_freea (pClassInstances);
}

void DeviceContext::DSSetSamplers (uint32 startSlot, array<ISamplerState^>^ samplerStates)
{
	if (samplerStates == nullptr || samplerStates->Length == 0)
		return;
	
	ID3D11SamplerState** pSamplerStates = (ID3D11SamplerState**)_malloca(sizeof(ID3D11SamplerState*)*samplerStates->Length);

	for (int i = 0 ; i < samplerStates->Length ; i++)
		pSamplerStates[i] = samplerStates[i] != nullptr ? ((SamplerState^)samplerStates[i])->GetNative() : nullptr;

	m_pDeviceContext->DSSetSamplers (startSlot, samplerStates->Length, pSamplerStates);

	_freea (pSamplerStates);
}

void DeviceContext::DSSetConstantBuffers (uint32 startSlot, array<IBuffer^>^ constantBuffers)
{
	if (constantBuffers == nullptr || constantBuffers->Length == 0)
		return;

	ID3D11Buffer** pBuffers = (ID3D11Buffer**)_malloca(sizeof(ID3D11Buffer*)*constantBuffers->Length);

	for (int i = 0 ; i < constantBuffers->Length ; i++)
		pBuffers[i] = constantBuffers[i] != nullptr ? ((Buffer^)constantBuffers[i])->GetNative() : nullptr;

	m_pDeviceContext->DSSetConstantBuffers (startSlot, constantBuffers->Length, pBuffers);

	_freea (pBuffers);
}

void DeviceContext::CSSetShaderResources (uint32 startSlot, array<IShaderResourceView^>^ shaderResourceViews)
{
	if (shaderResourceViews == nullptr || shaderResourceViews->Length == 0)
		return;
	
	ID3D11ShaderResourceView** pShaderResourceViews = (ID3D11ShaderResourceView**)_malloca(sizeof(ID3D11ShaderResourceView*)*shaderResourceViews->Length);

	for (int i = 0 ; i < shaderResourceViews->Length ; i++)
		pShaderResourceViews[i] = shaderResourceViews[i] != nullptr ? ((ShaderResourceView^)shaderResourceViews[i])->GetNative() : nullptr;

	m_pDeviceContext->DSSetShaderResources (startSlot, shaderResourceViews->Length, pShaderResourceViews);

	_freea (pShaderResourceViews);
}

void DeviceContext::CSSetUnorderedAccessViews(uint32 startSlot, array<IUnorderedAccessView^>^ unorderedAccessViews, array<uint32>^ uAVInitialCounts)
{
	if (unorderedAccessViews == nullptr || unorderedAccessViews->Length == 0 ||
		uAVInitialCounts == nullptr || uAVInitialCounts->Length != unorderedAccessViews->Length)
		return;
	
	ID3D11UnorderedAccessView** pUnorderedAccessViews = (ID3D11UnorderedAccessView**)_malloca(sizeof(ID3D11UnorderedAccessView*)*unorderedAccessViews->Length);
	UINT* pUAVInitialCounts= (UINT*)_malloca(sizeof(UINT)*uAVInitialCounts->Length);

	for (int i = 0 ; i < unorderedAccessViews->Length ; i++)
	{
		pUnorderedAccessViews[i] = unorderedAccessViews[i] != nullptr ? ((UnorderedAccessView^)unorderedAccessViews[i])->GetNative() : nullptr;
		pUAVInitialCounts[i] = uAVInitialCounts[i];
	}

	m_pDeviceContext->CSSetUnorderedAccessViews (startSlot, unorderedAccessViews->Length, pUnorderedAccessViews, pUAVInitialCounts);

	_freea (pUAVInitialCounts);
	_freea (pUnorderedAccessViews);
}

void DeviceContext::CSSetShader (IComputeShader^ computeShader, array<IClassInstance^>^ classInstances)
{
	ID3D11ComputeShader* pShader = computeShader != nullptr ? ((ComputeShader^)computeShader)->GetNative() : nullptr;

	ID3D11ClassInstance** pClassInstances = nullptr;
	UINT classInstancesCount = 0;

	if (classInstances != nullptr && classInstances->Length > 0)
	{
		pClassInstances = (ID3D11ClassInstance**)_malloca(sizeof(ID3D11ClassInstance*)*classInstances->Length);

		for (int i = 0 ; i < classInstances->Length ; i++)
			pClassInstances[i] = classInstances[i] != nullptr ? ((ClassInstance^)classInstances[i])->GetNative() : nullptr;

		classInstancesCount = classInstances->Length;
	}

	m_pDeviceContext->CSSetShader (pShader, pClassInstances, classInstancesCount);

	_freea (pClassInstances);
}

void DeviceContext::CSSetSamplers (uint32 startSlot, array<ISamplerState^>^ samplerStates)
{
	if (samplerStates == nullptr || samplerStates->Length == 0)
		return;
	
	ID3D11SamplerState** pSamplerStates = (ID3D11SamplerState**)_malloca(sizeof(ID3D11SamplerState*)*samplerStates->Length);

	for (int i = 0 ; i < samplerStates->Length ; i++)
		pSamplerStates[i] = samplerStates[i] != nullptr ? ((SamplerState^)samplerStates[i])->GetNative() : nullptr;

	m_pDeviceContext->CSSetSamplers (startSlot, samplerStates->Length, pSamplerStates);

	_freea (pSamplerStates);
}

void DeviceContext::CSSetConstantBuffers (uint32 startSlot, array<IBuffer^>^ constantBuffers)
{
	if (constantBuffers == nullptr || constantBuffers->Length == 0)
		return;

	ID3D11Buffer** pBuffers = (ID3D11Buffer**)_malloca(sizeof(ID3D11Buffer*)*constantBuffers->Length);

	for (int i = 0 ; i < constantBuffers->Length ; i++)
		pBuffers[i] = constantBuffers[i] != nullptr ? ((Buffer^)constantBuffers[i])->GetNative() : nullptr;

	m_pDeviceContext->CSSetConstantBuffers (startSlot, constantBuffers->Length, pBuffers);

	_freea (pBuffers);
}

ICommandList^ DeviceContext::FinishCommandList (bool restoreDeferredContextState)
{
	ID3D11CommandList* pCommandList;

	HRESULT hr = m_pDeviceContext->FinishCommandList (restoreDeferredContextState, &pCommandList);

	if (hr != S_OK)
		throw ref new Platform::COMException (hr);

	return ref new CommandList (pCommandList);
}

DeviceContextType DeviceContext::Type::get ()
{
	return (DeviceContextType)(m_pDeviceContext->GetType ());
}

uint32 DeviceContext::ContextFlags::get ()
{
	return m_pDeviceContext->GetContextFlags ();
}

///////////////////////////////////////////////////////////////////////////////////////////////////

ResourceDimension Resource::GetResourceDimenesion ()
{
	D3D11_RESOURCE_DIMENSION dimension;

	GetNativeResource()->GetType (&dimension);

	return (ResourceDimension)dimension;
}

uint32 Resource::GetEvictionPriority ()
{
	return GetNativeResource()->GetEvictionPriority();
}

void Resource::SetEvictionPriority (uint32 value)
{
	return GetNativeResource()->SetEvictionPriority(value);
}

///////////////////////////////////////////////////////////////////////////////////////////////////

Buffer::Buffer (ID3D11Buffer* pBuffer)
	: m_pBuffer (pBuffer)
	, m_pDesc (NULL)
{
}

Buffer::~Buffer ()
{
	if (m_pBuffer != nullptr)
	{
		m_pBuffer->Release ();
		m_pBuffer = nullptr;
	}

	delete m_pDesc;
}

void Buffer::UpdateDesc ()
{
	if (m_pDesc != NULL)
		return;

	m_pDesc = new D3D11_BUFFER_DESC;

	m_pBuffer->GetDesc (m_pDesc);
}


///////////////////////////////////////////////////////////////////////////////////////////////////

Texture1D::Texture1D (ID3D11Texture1D* pTexture1D)
	: m_pTexture1D (pTexture1D)
	, m_pDesc (NULL)
{
}

Texture1D::~Texture1D ()
{
	if (m_pTexture1D != nullptr)
	{
		m_pTexture1D->Release ();
		m_pTexture1D = nullptr;
	}

	delete m_pDesc;
}

void Texture1D::UpdateDesc ()
{
	if (m_pDesc != NULL)
		return;

	m_pDesc = new D3D11_TEXTURE1D_DESC;

	m_pTexture1D->GetDesc (m_pDesc);
}


///////////////////////////////////////////////////////////////////////////////////////////////////

Texture2D::Texture2D (ID3D11Texture2D* pTexture2D)
	: m_pTexture2D (pTexture2D)
	, m_pDesc (NULL)
{
}

Texture2D::~Texture2D ()
{
	if (m_pTexture2D != nullptr)
	{
		m_pTexture2D->Release ();
		m_pTexture2D = nullptr;
	}

	delete m_pDesc;
}

void Texture2D::UpdateDesc ()
{
	if (m_pDesc != NULL)
		return;

	m_pDesc = new D3D11_TEXTURE2D_DESC;

	m_pTexture2D->GetDesc (m_pDesc);
}

///////////////////////////////////////////////////////////////////////////////////////////////////

Texture3D::Texture3D (ID3D11Texture3D* pTexture3D)
	: m_pTexture3D (pTexture3D)
	, m_pDesc (NULL)
{
}

Texture3D::~Texture3D ()
{
	if (m_pTexture3D != nullptr)
	{
		m_pTexture3D->Release ();
		m_pTexture3D = nullptr;
	}

	delete m_pDesc;
}

void Texture3D::UpdateDesc ()
{
	if (m_pDesc != NULL)
		return;

	m_pDesc = new D3D11_TEXTURE3D_DESC;

	m_pTexture3D->GetDesc (m_pDesc);
}


///////////////////////////////////////////////////////////////////////////////////////////////////

DepthStencilView::DepthStencilView (ID3D11DepthStencilView* pDepthStencilView)
	: m_pDepthStencilView (pDepthStencilView)
{
}

DepthStencilView::~DepthStencilView ()
{
	if (m_pDepthStencilView != nullptr)
	{
		m_pDepthStencilView->Release ();
		m_pDepthStencilView = nullptr;
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////

RenderTargetView::RenderTargetView (ID3D11RenderTargetView* pRenderTargetView)
	: m_pRenderTargetView (pRenderTargetView)
{
}

RenderTargetView::~RenderTargetView ()
{
	if (m_pRenderTargetView != nullptr)
	{
		m_pRenderTargetView->Release ();
		m_pRenderTargetView = nullptr;
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////

ShaderResourceView::ShaderResourceView (ID3D11ShaderResourceView* pShaderResourceView)
	: m_pShaderResourceView (pShaderResourceView)
{
}

ShaderResourceView::~ShaderResourceView ()
{
	if (m_pShaderResourceView != nullptr)
	{
		m_pShaderResourceView->Release ();
		m_pShaderResourceView = nullptr;
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////

UnorderedAccessView::UnorderedAccessView (ID3D11UnorderedAccessView* pUnorderedAccessView)
	: m_pUnorderedAccessView (pUnorderedAccessView)
{
}

UnorderedAccessView::~UnorderedAccessView ()
{
	if (m_pUnorderedAccessView != nullptr)
	{
		m_pUnorderedAccessView->Release ();
		m_pUnorderedAccessView = nullptr;
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////

ComputeShader::ComputeShader (ID3D11ComputeShader* pComputeShader)
	: m_pComputeShader (pComputeShader)
{
}

ComputeShader::~ComputeShader ()
{
	if (m_pComputeShader != nullptr)
	{
		m_pComputeShader->Release ();
		m_pComputeShader = nullptr;
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////

DomainShader::DomainShader (ID3D11DomainShader* pDomainShader)
	: m_pDomainShader (pDomainShader)
{
}

DomainShader::~DomainShader ()
{
	if (m_pDomainShader != nullptr)
	{
		m_pDomainShader->Release ();
		m_pDomainShader = nullptr;
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////

GeometryShader::GeometryShader (ID3D11GeometryShader* pGeometryShader)
	: m_pGeometryShader (pGeometryShader)
{
}

GeometryShader::~GeometryShader ()
{
	if (m_pGeometryShader != nullptr)
	{
		m_pGeometryShader->Release ();
		m_pGeometryShader = nullptr;
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////

HullShader::HullShader (ID3D11HullShader* pHullShader)
	: m_pHullShader (pHullShader)
{
}

HullShader::~HullShader ()
{
	if (m_pHullShader != nullptr)
	{
		m_pHullShader->Release ();
		m_pHullShader = nullptr;
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////

PixelShader::PixelShader (ID3D11PixelShader* pPixelShader)
	: m_pPixelShader (pPixelShader)
{
}

PixelShader::~PixelShader ()
{
	if (m_pPixelShader != nullptr)
	{
		m_pPixelShader->Release ();
		m_pPixelShader = nullptr;
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////

VertexShader::VertexShader (ID3D11VertexShader* pVertexShader)
	: m_pVertexShader (pVertexShader)
{
}

VertexShader::~VertexShader ()
{
	if (m_pVertexShader != nullptr)
	{
		m_pVertexShader->Release ();
		m_pVertexShader = nullptr;
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////

BlendState::BlendState (ID3D11BlendState* pBlendState)
	: m_pBlendState (pBlendState)
{
}

BlendState::~BlendState ()
{
	if (m_pBlendState != nullptr)
	{
		m_pBlendState->Release ();
		m_pBlendState = nullptr;
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////

DepthStencilState::DepthStencilState (ID3D11DepthStencilState* pDepthStencilState)
	: m_pDepthStencilState (pDepthStencilState)
{
}

DepthStencilState::~DepthStencilState ()
{
	if (m_pDepthStencilState != nullptr)
	{
		m_pDepthStencilState->Release ();
		m_pDepthStencilState = nullptr;
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////

RasterizerState::RasterizerState (ID3D11RasterizerState* pRasterizerState)
	: m_pRasterizerState (pRasterizerState)
{
}

RasterizerState::~RasterizerState ()
{
	if (m_pRasterizerState != nullptr)
	{
		m_pRasterizerState->Release ();
		m_pRasterizerState = nullptr;
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////

SamplerState::SamplerState (ID3D11SamplerState* pSamplerState)
	: m_pSamplerState (pSamplerState)
{
}

SamplerState::~SamplerState ()
{
	if (m_pSamplerState != nullptr)
	{
		m_pSamplerState->Release ();
		m_pSamplerState = nullptr;
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////

InputLayout::InputLayout (ID3D11InputLayout* pInputLayout)
	: m_pInputLayout (pInputLayout)
{
}

InputLayout::~InputLayout ()
{
	if (m_pInputLayout != nullptr)
	{
		m_pInputLayout->Release ();
		m_pInputLayout = nullptr;
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////

ClassInstance::ClassInstance (ID3D11ClassInstance* pClassInstance)
	: m_pClassInstance (pClassInstance)
{
}

ClassInstance::~ClassInstance ()
{
	if (m_pClassInstance != nullptr)
	{
		m_pClassInstance->Release ();
		m_pClassInstance = nullptr;
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////

ClassLinkage::ClassLinkage (ID3D11ClassLinkage* pClassLinkage)
	: m_pClassLinkage (pClassLinkage)
{
}

ClassLinkage::~ClassLinkage ()
{
	if (m_pClassLinkage != nullptr)
	{
		m_pClassLinkage->Release ();
		m_pClassLinkage = nullptr;
	}
}


///////////////////////////////////////////////////////////////////////////////////////////////////

CommandList::CommandList (ID3D11CommandList* pCommandList)
	: m_pCommandList (pCommandList)
{
}

CommandList::~CommandList ()
{
	if (m_pCommandList != nullptr)
	{
		m_pCommandList->Release ();
		m_pCommandList = nullptr;
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////

Query::Query (ID3D11Query* pQuery)
	: m_pQuery (pQuery)
{
}

Query::~Query ()
{
	if (m_pQuery != nullptr)
	{
		m_pQuery->Release ();
		m_pQuery = nullptr;
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////

Predicate::Predicate (ID3D11Predicate* pPredicate)
	: m_pPredicate (pPredicate)
{
}

Predicate::~Predicate ()
{
	if (m_pPredicate != nullptr)
	{
		m_pPredicate->Release ();
		m_pPredicate = nullptr;
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////

Counter::Counter (ID3D11Counter* pCounter)
	: m_pCounter (pCounter)
{
}

Counter::~Counter ()
{
	if (m_pCounter != nullptr)
	{
		m_pCounter->Release ();
		m_pCounter = nullptr;
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////
